{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import pandas as pd\n",
    "import copy\n",
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = np.array([[2104, 5, 1, 45], [1416, 3, 2, 40], [852, 2, 1, 35]])\n",
    "y_train = np.array([460, 232, 178])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w_init shape: (4,), b_init type: <class 'float'>\n"
     ]
    }
   ],
   "source": [
    "b_init = 785.1811367994083\n",
    "w_init = np.array([ 0.39133535, 18.75376741, -53.36032453, -26.42131618])\n",
    "print(f\"w_init shape: {w_init.shape}, b_init type: {type(b_init)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Prediction using predefined W and B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict_loop(x, w, b):\n",
    "  n = x.shape[0]\n",
    "  p = 0\n",
    "  for i in range(n):\n",
    "    p += w[i] * x[i]\n",
    "  p += b\n",
    "  return p\n",
    "\n",
    "def predict_vectorized(x, w, b):\n",
    "  return np.dot(w, x) + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "459.9999976194083\n",
      "459.9999976194082\n"
     ]
    }
   ],
   "source": [
    "x_vec = x_train[0, :] # all features of the first row\n",
    "print(predict_loop(x_vec, w_init, b_init))\n",
    "print(predict_vectorized(x_vec, w_init, b_init))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Computing Cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_cost(x, y, w, b):\n",
    "  m = x.shape[0]\n",
    "  cost = 0.0\n",
    "\n",
    "  for i in range(m):\n",
    "    f_wb = np.dot(x[i], w) + b\n",
    "    cost += (f_wb - y[i])**2\n",
    "\n",
    "  cost /= 2*m\n",
    "  return cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.5578904330213735e-12\n"
     ]
    }
   ],
   "source": [
    "cost = compute_cost(x_train, y_train, w_init, b_init)\n",
    "print(cost)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Gradient Descent with Multiple Values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_gradient(x, y, w, b):\n",
    "  m, n = x.shape\n",
    "  dj_dw = np.zeros(n)\n",
    "  dj_db = 0.0\n",
    "\n",
    "  for i in range(m):\n",
    "    err = (np.dot(x[i], w) + b) - y[i]\n",
    "    for j in range(n):\n",
    "      dj_dw[j] += err * x[i, j]\n",
    "    dj_db += err\n",
    "  \n",
    "  dj_dw /= m\n",
    "  dj_db /= m\n",
    "\n",
    "  return dj_dw, dj_db\n",
    "\n",
    "def gradient_descent(x, y, w, b, alpha, num_iters, cost):\n",
    "  J_history = []\n",
    "  w = copy.deepcopy(w)\n",
    "\n",
    "  for i in range(num_iters):\n",
    "    dj_dw, dj_db = compute_gradient(x, y, w, b)\n",
    "    w -= alpha * dj_dw\n",
    "    b -= alpha * dj_db\n",
    "\n",
    "    if i < 100000:\n",
    "      J_history.append(cost(x, y, w, b))\n",
    "    \n",
    "    if i% math.ceil(num_iters/10) == 0:\n",
    "      print(\"Iteration {:4d}, cost is {:8.2f}\".format(i,J_history[-1]))\n",
    "\n",
    "  return w, b, J_history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Iteration    0, cost is  2529.46\n",
      "Iteration 10000, cost is   624.82\n",
      "Iteration 20000, cost is   594.33\n",
      "Iteration 30000, cost is   581.01\n",
      "Iteration 40000, cost is   574.73\n",
      "Iteration 50000, cost is   571.36\n",
      "Iteration 60000, cost is   569.18\n",
      "Iteration 70000, cost is   567.49\n",
      "Iteration 80000, cost is   566.01\n",
      "Iteration 90000, cost is   564.61\n"
     ]
    }
   ],
   "source": [
    "w = np.zeros_like(w_init)\n",
    "b = 0.0\n",
    "alpha = 5.0e-7\n",
    "iterations = 100000\n",
    "\n",
    "w_final , b_final, J_hist = gradient_descent(x_train, y_train, w, b, alpha, iterations, compute_cost)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b,w found by gradient descent: -0.00, [ 0.20396569  0.00374919 -0.0112487  -0.0658614 ]\n"
     ]
    }
   ],
   "source": [
    "print(f\"b,w found by gradient descent: {b_final:0.2f}, {w_final}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlYAAAHFCAYAAAAwv7dvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABIkklEQVR4nO3de1xVdb7/8fdGYQuEWxBhS5GXvKRhltZ4qVErJS9onc5vuqhk2dBlQqX0VE7NaFZYNjmdMrM6k3anM1M2nTJGS6Ucb4RS3iqbTLyAmuIGL1yE7+8PDvu4BRVww4LF6/l47MeGtT5rre+Xvbf77fe79toOY4wRAAAAzlmA1Q0AAACwC4IVAACAnxCsAAAA/IRgBQAA4CcEKwAAAD8hWAEAAPgJwQoAAMBPCFYAAAB+QrACAADwE4IVYBOLFi2Sw+E47W3lypVWN7FRONPfyJ9/r5kzZ8rhcNRp25UrV1r2mFUe+3S3RYsWNXibTuVwOJScnGx1M4BqtbS6AQD8a+HChbr44ourLO/Zs6cFrWl81qxZ4/P7E088oRUrVmj58uU+y8/17/Xb3/5Ww4cPr9O2ffr00Zo1ayx9zFJTU3XNNddUWX7RRRdZ0Bqg6SBYATYTFxenK664olbbGGNUVFSk4ODgKuuOHz+uVq1a1Xn0RZKOHTumkJCQOm/vT/379/f5vV27dgoICKiy/FS17cMFF1ygCy64oE5tbN269VnbU9+6du1qeRuApoipQKAZqpxKWbBggXr06CGn06k33njDO524dOlSTZw4Ue3atVNISIiKi4tVXl6uOXPm6OKLL5bT6VRUVJRuv/127d6922ffQ4YMUVxcnL788ksNHDhQISEhmjhxYrXteP755+VwOPTjjz9WWffwww8rKChIv/zyiyRp48aNSkhIUFRUlJxOp2JiYjRq1Kgqx/eHM/Xh/fffV3x8vNq3b6/g4GD16NFDjzzyiI4ePeqzj+qmAjt27KiEhASlp6erT58+Cg4O1sUXX6zXX3/dp666qcA77rhD5513nn788UeNHDlS5513nmJjYzV16lQVFxf7bL979279v//3/xQWFqY2bdpo3LhxyszM9PtUXmV/Fi9erEsvvVStWrVS586d9cILL1SpzcnJ0fjx472PX48ePfTcc8+pvLzcp664uFizZs1Sjx491KpVK7Vt21bXXHONVq9eXWWfb731lnr06KGQkBD17t1bn3zyid/6BtQVI1aAzZSVlenEiRM+yxwOh1q0aOGz7KOPPtJXX32lP/7xj3K73YqKilJmZqYkaeLEiRo1apTeeustHT16VIGBgbrvvvv06quvKjk5WQkJCfr555/1hz/8QStXrtSGDRsUGRnp3Xdubq7Gjx+vhx56SKmpqQoIqP7/cOPHj9fDDz+sRYsW6cknn/Tpw9tvv63Ro0crMjJSR48e1bBhw9SpUye99NJLio6OVl5enlasWKHCwkJ//el8nK4P27dv18iRI5WSkqLQ0FB99913euaZZ7R+/foq04nV+eabbzR16lQ98sgjio6O1n/913/prrvuUpcuXTRo0KAzbltaWqoxY8borrvu0tSpU/Xll1/qiSeekMvl0h//+EdJ0tGjR3XNNdfo0KFDeuaZZ9SlSxelp6frlltuqVX/y8vLqzyPJKllS9+3jezsbKWkpGjmzJlyu9165513NGXKFJWUlGjatGmSpAMHDmjgwIEqKSnRE088oY4dO+qTTz7RtGnT9K9//Uvz58+XJJ04cUIjRozQV199pZSUFF177bU6ceKE1q5dq5ycHA0cONB73E8//VSZmZmaNWuWzjvvPM2ZM0f/9m//pu+//16dO3euVV8BvzIAbGHhwoVGUrW3Fi1a+NRKMi6Xyxw6dKjafdx+++0+y7dt22Ykmd/97nc+y9etW2ckmd///vfeZYMHDzaSzBdffFGjdt90003mggsuMGVlZd5lS5YsMZLM//zP/xhjjPn666+NJPPRRx/VaJ+1MWHCBBMaGuqzrKZ9KC8vN6WlpSYjI8NIMt9884133YwZM8yp/8R26NDBtGrVyuzcudO77Pjx4yYiIsLcc8893mUrVqwwksyKFSt82inJ/Pd//7fPPkeOHGm6d+/u/f2ll14yksxnn33mU3fPPfcYSWbhwoVn7FPlsU9327Vrl09/HA6Hyc7O9tnHsGHDTOvWrc3Ro0eNMcY88sgjRpJZt26dT919991nHA6H+f77740xxrz55ptGknnttdfO2EZJJjo62hQUFHiX5eXlmYCAADN79uwzbgvUN6YCAZt58803lZmZ6XNbt25dlbprr71W4eHh1e7j3//9331+X7FihaSK6aiT/epXv1KPHj30xRdf+CwPDw/XtddeW6P23nnnndq9e7c+//xz77KFCxfK7XZrxIgRkqQuXbooPDxcDz/8sBYsWKCtW7fWaN/n4nR9+OmnnzR27Fi53W61aNFCgYGBGjx4sCRp27ZtZ93vZZddpgsvvND7e6tWrdStWzft3LnzrNs6HA6NHj3aZ9mll17qs21GRobCwsKqnDh/2223nXX/J3vmmWeqPI8yMzMVHR3tU3fJJZeod+/ePsvGjh2rgoICbdiwQZK0fPly9ezZU7/61a986u644w4ZY7wjfZ999platWp12qnjk11zzTUKCwvz/h4dHa2oqKga/R2B+sRUIGAzPXr0qNHJ6+3bt6/xuoMHD552m5iYmCpvZmfa96lGjBih9u3ba+HChYqPj1d+fr4+/vhjTZkyxTt96XK5lJGRoaeeekq///3vlZ+fr/bt2yspKUmPPfaYAgMDa3y8mqquD0eOHNGvf/1rtWrVSk8++aS6deumkJAQ7dq1SzfddJOOHz9+1v22bdu2yjKn01mjbUNCQtSqVasq2xYVFXl/P3jwYJXwI6naZWfSuXPnGj2P3G73aZdVPm8OHjyojh07VqmLiYnxqTtw4IBiYmJOO3V8snP5OwL1iWAFNFNn+pTfqesq38Ryc3OrfNJt7969PudXnW3fp2rRooUSExP1wgsv6PDhw3r33XdVXFysO++806euV69eSktLkzFG3377rRYtWqRZs2YpODhYjzzySI2PV1PV9WH58uXau3evVq5c6R2lkqTDhw/7/fh11bZtW61fv77K8ry8vHo5XnX7rVxW+bxp27atcnNzq9Tt3btXkrzPn3bt2mnVqlUqLy+vUbgCGiOeuQDOqnJK7O233/ZZnpmZqW3btum66647p/3feeedKioq0nvvvadFixZpwIAB1V6LS6oIPL1799af//xntWnTxjvd1BAqw5bT6fRZ/sorrzRYG85m8ODBKiws1GeffeazPC0trV6Ot2XLFn3zzTc+y959912FhYWpT58+kqTrrrtOW7durfJYvfnmm3I4HN7rZY0YMUJFRUWN4iKkQF0xYgXYzObNm6v9NNdFF12kdu3a1Wmf3bt31913360XX3xRAQEBGjFihPdTgbGxsXrggQfOqc0XX3yxBgwYoNmzZ2vXrl169dVXfdZ/8sknmj9/vm688UZ17txZxhh9+OGHOnz4sIYNG+atu+6665SRkVFt//1h4MCBCg8P17333qsZM2YoMDBQ77zzTpVgYaUJEyboz3/+s8aPH68nn3xSXbp00WeffaZ//OMfklTjkaDt27dr7dq1VZafen2umJgYjRkzRjNnzlT79u319ttva9myZXrmmWe81/164IEH9Oabb2rUqFGaNWuWOnTooE8//VTz58/Xfffdp27dukmqOA9s4cKFuvfee/X999/rmmuuUXl5udatW6cePXro1ltvPdc/D1DvCFaAzZw6hVbptdde029/+9s67/fll1/WRRddpL/85S966aWX5HK5NHz4cM2ePbva811q684779Tdd9+t4ODgKpcG6Nq1q9q0aaM5c+Zo7969CgoKUvfu3bVo0SJNmDDBW1dWVqaysrJzbsvptG3bVp9++qmmTp2q8ePHKzQ0VDfccIPef/997+iM1UJDQ7V8+XKlpKTooYceksPhUHx8vObPn6+RI0eqTZs2NdrP73//+2qXP/rooz6Xxrjssst05513asaMGdq+fbtiYmI0d+5cn7Ddrl07rV69WtOnT9f06dNVUFCgzp07a86cOXrwwQe9dS1bttSSJUs0e/Zsvffee3r++ecVFham3r171/kq9kBDcxhjjNWNAADUr9TUVD322GPKycmp8xXhT9WxY0fFxcVxYU7gJIxYAYDNzJs3T1LFFGtpaamWL1+uF154QePHj/dbqAJQPYIVANhMSEiI/vznP+vnn39WcXGxLrzwQj388MN67LHHrG4aYHtMBQIAAPgJl1sAAADwE4IVAACAnxCsAAAA/IST1xtYeXm59u7dq7CwsFp97QcAALCOMUaFhYVn/T5LglUD27t3r2JjY61uBgAAqINdu3ad8bIlBKsGFhYWJqnigWndurXFrQEAADVRUFCg2NhY7/v46RCsGljl9F/r1q0JVgAANDFnO42Hk9cBAAD8hGAFAADgJwQrAAAAPyFYAQAA+AnBCgAAwE8IVgAAAH5CsAIAAPATghUAAICfEKwAAAD8hGAFAADgJ5YGqy+//FKjR49WTEyMHA6HPvroI5/1xhjNnDlTMTExCg4O1pAhQ7RlyxafmuLiYk2aNEmRkZEKDQ3VmDFjtHv3bp+a/Px8JSYmyuVyyeVyKTExUYcPH/apycnJ0ejRoxUaGqrIyEhNnjxZJSUlPjWbNm3S4MGDFRwcrPPPP1+zZs2SMcZvfw8AANC0WRqsjh49qt69e2vevHnVrp8zZ47mzp2refPmKTMzU263W8OGDVNhYaG3JiUlRYsXL1ZaWppWrVqlI0eOKCEhQWVlZd6asWPHKjs7W+np6UpPT1d2drYSExO968vKyjRq1CgdPXpUq1atUlpamj744ANNnTrVW1NQUKBhw4YpJiZGmZmZevHFF/WnP/1Jc+fOrYe/DAAAaJJMIyHJLF682Pt7eXm5cbvd5umnn/YuKyoqMi6XyyxYsMAYY8zhw4dNYGCgSUtL89bs2bPHBAQEmPT0dGOMMVu3bjWSzNq1a701a9asMZLMd999Z4wxZsmSJSYgIMDs2bPHW/Pee+8Zp9NpPB6PMcaY+fPnG5fLZYqKirw1s2fPNjExMaa8vLzG/fR4PEaSd7/+kpNjzI4dxpSW+nW3AADA1Pz9u9GeY7Vjxw7l5eUpPj7eu8zpdGrw4MFavXq1JCkrK0ulpaU+NTExMYqLi/PWrFmzRi6XS/369fPW9O/fXy6Xy6cmLi5OMTEx3prrr79excXFysrK8tYMHjxYTqfTp2bv3r36+eefT9uP4uJiFRQU+NzqQ5cuUqdOUl5eveweAADUQKMNVnn/mxCio6N9lkdHR3vX5eXlKSgoSOHh4WesiYqKqrL/qKgon5pTjxMeHq6goKAz1lT+nneGNDN79mzvuV0ul0uxsbFn7ngdBfzvI3nSDCgAAGhgjTZYVXI4HD6/G2OqLDvVqTXV1fujxvzvietnas/06dPl8Xi8t127dp2x7XVVGazKy+tl9wAAoAYabbByu92Sqo4G7d+/3ztS5Ha7VVJSovz8/DPW7Nu3r8r+Dxw44FNz6nHy8/NVWlp6xpr9+/dLqjqqdjKn06nWrVv73OpDixYV9wQrAACs02iDVadOneR2u7Vs2TLvspKSEmVkZGjgwIGSpL59+yowMNCnJjc3V5s3b/bWDBgwQB6PR+vXr/fWrFu3Th6Px6dm8+bNys3N9dYsXbpUTqdTffv29dZ8+eWXPpdgWLp0qWJiYtSxY0f//wFqialAAACsZ2mwOnLkiLKzs5WdnS2p4oT17Oxs5eTkyOFwKCUlRampqVq8eLE2b96sO+64QyEhIRo7dqwkyeVy6a677tLUqVP1xRdfaOPGjRo/frx69eqloUOHSpJ69Oih4cOHKykpSWvXrtXatWuVlJSkhIQEde/eXZIUHx+vnj17KjExURs3btQXX3yhadOmKSkpyTvCNHbsWDmdTt1xxx3avHmzFi9erNTUVD344INnnZpsCIxYAQDQCNT/BxRPb8WKFUZSlduECROMMRWXXJgxY4Zxu93G6XSaQYMGmU2bNvns4/jx4yY5OdlERESY4OBgk5CQYHJycnxqDh48aMaNG2fCwsJMWFiYGTdunMnPz/ep2blzpxk1apQJDg42ERERJjk52efSCsYY8+2335pf//rXxul0GrfbbWbOnFmrSy0YU3+XW4iMNEYyZssWv+4WAACYmr9/O4zh0uENqaCgQC6XSx6Px6/nW0VHS/v3S99+K/Xq5bfdAgAA1fz9u9GeY4XaYSoQAADrEaxsgsstAABgPYKVTfCpQAAArEewsgmmAgEAsB7ByiaYCgQAwHoEK5tgKhAAAOsRrGyCqUAAAKxHsLIJpgIBALAewcommAoEAMB6BCubYCoQAADrEaxsgqlAAACsR7CyCaYCAQCwHsHKJpgKBADAegQrm2DECgAA6xGsbIJzrAAAsB7ByiaYCgQAwHoEK5tgKhAAAOsRrGyicsSKYAUAgHUIVjZROWJljLXtAACgOSNY2QRTgQAAWI9gZRNMBQIAYD2ClU3wqUAAAKxHsLIJpgIBALAewcomGLECAMB6BCubYMQKAADrEaxsghErAACsR7CyCUasAACwHsHKJhixAgDAegQrm2DECgAA6xGsbIILhAIAYD2ClU1UjlgxFQgAgHUIVjbBiBUAANYjWNkEI1YAAFiPYGUTjFgBAGA9gpVNMGIFAID1CFY2wYgVAADWI1jZBBcIBQDAegQrm+ACoQAAWI9gZROMWAEAYD2ClU0wYgUAgPUIVjbByesAAFiPYGUTXG4BAADrEaxsghErAACsR7CyCUasAACwHsHKJhixAgDAegQrm2DECgAA6xGsbIIRKwAArEewsglGrAAAsB7ByiYYsQIAwHoEK5sgWAEAYD2ClU0wFQgAgPUIVjbBiBUAANYjWNkEI1YAAFiPYGUTjFgBAGA9gpVNMGIFAID1CFY2wYgVAADWa9TB6sSJE3rsscfUqVMnBQcHq3Pnzpo1a5bKTxqWMcZo5syZiomJUXBwsIYMGaItW7b47Ke4uFiTJk1SZGSkQkNDNWbMGO3evdunJj8/X4mJiXK5XHK5XEpMTNThw4d9anJycjR69GiFhoYqMjJSkydPVklJSb31vzYYsQIAwHqNOlg988wzWrBggebNm6dt27Zpzpw5evbZZ/Xiiy96a+bMmaO5c+dq3rx5yszMlNvt1rBhw1RYWOitSUlJ0eLFi5WWlqZVq1bpyJEjSkhIUNlJwztjx45Vdna20tPTlZ6eruzsbCUmJnrXl5WVadSoUTp69KhWrVqltLQ0ffDBB5o6dWrD/DHOghErAAAaAdOIjRo1ykycONFn2U033WTGjx9vjDGmvLzcuN1u8/TTT3vXFxUVGZfLZRYsWGCMMebw4cMmMDDQpKWleWv27NljAgICTHp6ujHGmK1btxpJZu3atd6aNWvWGEnmu+++M8YYs2TJEhMQEGD27NnjrXnvvfeM0+k0Ho+nxn3yeDxGUq22qYm0NGMkY4YM8etuAQCAqfn7d6Mesbr66qv1xRdf6IcffpAkffPNN1q1apVGjhwpSdqxY4fy8vIUHx/v3cbpdGrw4MFavXq1JCkrK0ulpaU+NTExMYqLi/PWrFmzRi6XS/369fPW9O/fXy6Xy6cmLi5OMTEx3prrr79excXFysrKOm0fiouLVVBQ4HOrD4xYAQBgvZZWN+BMHn74YXk8Hl188cVq0aKFysrK9NRTT+m2226TJOXl5UmSoqOjfbaLjo7Wzp07vTVBQUEKDw+vUlO5fV5enqKioqocPyoqyqfm1OOEh4crKCjIW1Od2bNn6/HHH69Nt+uk8hwrghUAANZp1CNW77//vt5++229++672rBhg9544w396U9/0htvvOFT53A4fH43xlRZdqpTa6qrr0vNqaZPny6Px+O97dq164ztqqvKEStOXgcAwDqNesTqP/7jP/TII4/o1ltvlST16tVLO3fu1OzZszVhwgS53W5JFaNJ7du39263f/9+7+iS2+1WSUmJ8vPzfUat9u/fr4EDB3pr9u3bV+X4Bw4c8NnPunXrfNbn5+ertLS0ykjWyZxOp5xOZ126XytMBQIAYL1GPWJ17NgxBQT4NrFFixbeyy106tRJbrdby5Yt864vKSlRRkaGNzT17dtXgYGBPjW5ubnavHmzt2bAgAHyeDxav369t2bdunXyeDw+NZs3b1Zubq63ZunSpXI6nerbt6+fe157XG4BAADrNeoRq9GjR+upp57ShRdeqEsuuUQbN27U3LlzNXHiREkVU3MpKSlKTU1V165d1bVrV6WmpiokJERjx46VJLlcLt11112aOnWq2rZtq4iICE2bNk29evXS0KFDJUk9evTQ8OHDlZSUpFdeeUWSdPfddyshIUHdu3eXJMXHx6tnz55KTEzUs88+q0OHDmnatGlKSkpS69atLfjr+GLECgCARqABPqFYZwUFBWbKlCnmwgsvNK1atTKdO3c2jz76qCkuLvbWlJeXmxkzZhi3222cTqcZNGiQ2bRpk89+jh8/bpKTk01ERIQJDg42CQkJJicnx6fm4MGDZty4cSYsLMyEhYWZcePGmfz8fJ+anTt3mlGjRpng4GATERFhkpOTTVFRUa36VF+XW1i6tOJyC5de6tfdAgAAU/P3b4cxxlgd7pqTgoICuVwueTwev450LV8uXXeddMkl0ubNftstAABQzd+/G/U5Vqg5zrECAMB6BCub4BwrAACsR7CyCUasAACwHsHKJhixAgDAegQrm+ArbQAAsB7Byib4ShsAAKxHsLIJRqwAALAewcomGLECAMB6BCub4OR1AACsR7CyCS63AACA9QhWNsGIFQAA1iNY2QQjVgAAWI9gZROMWAEAYD2ClU1wuQUAAKxHsLIJLrcAAID1CFY2wYgVAADWI1jZBCNWAABYj2BlEwEnPZKEKwAArEGwsonKESuJYAUAgFUIVjZx8ogV51kBAGANgpVNMGIFAID1CFY2cXKwYsQKAABrEKxsgpPXAQCwHsHKJhixAgDAegQrm+DkdQAArEewsgmmAgEAsB7ByiYcjoqbxIgVAABWIVjZCF9rAwCAtQhWNsIXMQMAYC2ClY0wYgUAgLUIVjbCiBUAANYiWNkII1YAAFiLYGUjjFgBAGAtgpWNVI5YEawAALAGwcpGmAoEAMBaBCsbYSoQAABrEaxshBErAACsRbCyEUasAACwFsHKRhixAgDAWgQrG2HECgAAaxGsbKRly4p7ghUAANYgWNlI5VTgiRPWtgMAgOaKYGUjXCAUAABrEaxshKlAAACsRbCyEaYCAQCwFsHKRpgKBADAWgQrG2EqEAAAaxGsbISpQAAArEWwshGmAgEAsBbBykaYCgQAwFoEKxthKhAAAGsRrGyEqUAAAKxFsLIRpgIBALAWwcpGGLECAMBaBCsb4RwrAACsRbCyEaYCAQCwVqMPVnv27NH48ePVtm1bhYSE6LLLLlNWVpZ3vTFGM2fOVExMjIKDgzVkyBBt2bLFZx/FxcWaNGmSIiMjFRoaqjFjxmj37t0+Nfn5+UpMTJTL5ZLL5VJiYqIOHz7sU5OTk6PRo0crNDRUkZGRmjx5skpKSuqt77XFVCAAANZq1MEqPz9fV111lQIDA/XZZ59p69ateu6559SmTRtvzZw5czR37lzNmzdPmZmZcrvdGjZsmAoLC701KSkpWrx4sdLS0rRq1SodOXJECQkJKjspgYwdO1bZ2dlKT09Xenq6srOzlZiY6F1fVlamUaNG6ejRo1q1apXS0tL0wQcfaOrUqQ3yt6gJpgIBALCYacQefvhhc/XVV592fXl5uXG73ebpp5/2LisqKjIul8ssWLDAGGPM4cOHTWBgoElLS/PW7NmzxwQEBJj09HRjjDFbt241kszatWu9NWvWrDGSzHfffWeMMWbJkiUmICDA7Nmzx1vz3nvvGafTaTweT4375PF4jKRabVNTEycaIxmTmur3XQMA0KzV9P27UY9Yffzxx7riiiv0m9/8RlFRUbr88sv12muvedfv2LFDeXl5io+P9y5zOp0aPHiwVq9eLUnKyspSaWmpT01MTIzi4uK8NWvWrJHL5VK/fv28Nf3795fL5fKpiYuLU0xMjLfm+uuvV3Fxsc/U5KmKi4tVUFDgc6svTAUCAGCtRh2sfvrpJ7388svq2rWr/vGPf+jee+/V5MmT9eabb0qS8vLyJEnR0dE+20VHR3vX5eXlKSgoSOHh4WesiYqKqnL8qKgon5pTjxMeHq6goCBvTXVmz57tPW/L5XIpNja2Nn+CWmEqEAAAazXqYFVeXq4+ffooNTVVl19+ue655x4lJSXp5Zdf9qlzOBw+vxtjqiw71ak11dXXpeZU06dPl8fj8d527dp1xnadCz4VCACAtRp1sGrfvr169uzps6xHjx7KycmRJLndbkmqMmK0f/9+7+iS2+1WSUmJ8vPzz1izb9++Ksc/cOCAT82px8nPz1dpaWmVkayTOZ1OtW7d2udWX5gKBADAWo06WF111VX6/vvvfZb98MMP6tChgySpU6dOcrvdWrZsmXd9SUmJMjIyNHDgQElS3759FRgY6FOTm5urzZs3e2sGDBggj8ej9evXe2vWrVsnj8fjU7N582bl5uZ6a5YuXSqn06m+ffv6ued1Q7ACAMBaLa1uwJk88MADGjhwoFJTU3XzzTdr/fr1evXVV/Xqq69KqpiaS0lJUWpqqrp27aquXbsqNTVVISEhGjt2rCTJ5XLprrvu0tSpU9W2bVtFRERo2rRp6tWrl4YOHSqpYhRs+PDhSkpK0iuvvCJJuvvuu5WQkKDu3btLkuLj49WzZ08lJibq2Wef1aFDhzRt2jQlJSXV6yhUbVROBXKOFQAAFmmATyiek//5n/8xcXFxxul0mosvvti8+uqrPuvLy8vNjBkzjNvtNk6n0wwaNMhs2rTJp+b48eMmOTnZREREmODgYJOQkGBycnJ8ag4ePGjGjRtnwsLCTFhYmBk3bpzJz8/3qdm5c6cZNWqUCQ4ONhERESY5OdkUFRXVqj/1ebmF6dMrLrcwZYrfdw0AQLNW0/dvhzHGWB3umpOCggK5XC55PB6/j3T94Q/Sk09KycnSiy/6ddcAADRrNX3/btTnWKF2mAoEAMBaBCsb4eR1AACsRbCyEYIVAADWIljZCFOBAABYi2BlI4xYAQBgLYKVjRCsAACwFsHKRpgKBADAWgQrG2HECgAAaxGsbIRgBQCAtQhWNlI5FUiwAgDAGgQrG6kcseIcKwAArEGwshGmAgEAsBbBykYIVgAAWItgZSNcbgEAAGvVKVjNmjVLx44dq7L8+PHjmjVr1jk3CnXDiBUAANaqU7B6/PHHdeTIkSrLjx07pscff/ycG4W6YcQKAABr1SlYGWPkcDiqLP/mm28UERFxzo1C3RCsAACwVsvaFIeHh8vhcMjhcKhbt24+4aqsrExHjhzRvffe6/dGomYCAyvuS0utbQcAAM1VrYLV888/L2OMJk6cqMcff1wul8u7LigoSB07dtSAAQP83kjUDMEKAABr1SpYTZgwQZLUqVMnXXXVVWrZslabo54RrAAAsFadzrEKCwvTtm3bvL///e9/14033qjf//73Kikp8VvjUDucYwUAgLXqFKzuuece/fDDD5Kkn376SbfccotCQkL017/+VQ899JBfG4iaY8QKAABr1SlY/fDDD7rsssskSX/96181ePBgvfvuu1q0aJE++OADf7YPtUCwAgDAWnW+3EJ5ebkk6fPPP9fIkSMlSbGxsfrll1/81zrUCsEKAABr1SlYXXHFFXryySf11ltvKSMjQ6NGjZIk7dixQ9HR0X5tIGqu8hwrghUAANaoU7B6/vnntWHDBiUnJ+vRRx9Vly5dJEl/+9vfNHDgQL82EDVXOWLFyesAAFjDYYwx/tpZUVGRWrRoocDKd3hUUVBQIJfLJY/Ho9atW/t137m5UkyMFBDA9wUCAOBPNX3/PqcLUWVlZWnbtm1yOBzq0aOH+vTpcy67wzmqzLPl5RW3gDqNRwIAgLqqU7Dav3+/brnlFmVkZKhNmzYyxsjj8eiaa65RWlqa2rVr5+92ogZOvl5raankdFrXFgAAmqM6jWlMmjRJhYWF2rJliw4dOqT8/Hxt3rxZBQUFmjx5sr/biBo6eQaWE9gBAGh4dRqxSk9P1+eff64ePXp4l/Xs2VMvvfSS4uPj/dY41M7JwYoT2AEAaHh1GrEqLy+v9gT1wMBA7/Wt0PBOnQoEAAANq07B6tprr9WUKVO0d+9e77I9e/bogQce0HXXXee3xqF2AgL+74R1ghUAAA2vTsFq3rx5KiwsVMeOHXXRRRepS5cu6tSpkwoLC/Xiiy/6u42oBa6+DgCAdep0jlVsbKw2bNigZcuW6bvvvpMxRj179tTQoUP93T7UUmCgVFzMOVYAAFihViNWy5cvV8+ePVVQUCBJGjZsmCZNmqTJkyfryiuv1CWXXKKvvvqqXhqKmmHECgAA69QqWD3//PNKSkqq9oqjLpdL99xzj+bOneu3xqH2+L5AAACsU6tg9c0332j48OGnXR8fH6+srKxzbhTqjhErAACsU6tgtW/fvjN+D2DLli114MCBc24U6o5gBQCAdWoVrM4//3xt2rTptOu//fZbtW/f/pwbhbqrDFacvA4AQMOrVbAaOXKk/vjHP6qoqKjKuuPHj2vGjBlKSEjwW+NQe5xjBQCAdWp1uYXHHntMH374obp166bk5GR1795dDodD27Zt00svvaSysjI9+uij9dVW1ABTgQAAWKdWwSo6OlqrV6/Wfffdp+nTp8sYI0lyOBy6/vrrNX/+fEVHR9dLQ1EzBCsAAKxT6wuEdujQQUuWLFF+fr5+/PFHGWPUtWtXhYeH10f7UEsEKwAArFOnK69LUnh4uK688kp/tgV+EBRUcV9SYm07AABojur0XYFovJzOivviYmvbAQBAc0SwshmCFQAA1iFY2QzBCgAA6xCsbIZgBQCAdQhWNkOwAgDAOgQrmyFYAQBgHYKVzVQGKy63AABAwyNY2UzldawYsQIAoOERrGyGqUAAAKxDsLIZghUAANYhWNkMwQoAAOs0qWA1e/ZsORwOpaSkeJcZYzRz5kzFxMQoODhYQ4YM0ZYtW3y2Ky4u1qRJkxQZGanQ0FCNGTNGu3fv9qnJz89XYmKiXC6XXC6XEhMTdfjwYZ+anJwcjR49WqGhoYqMjNTkyZNV0sjOEidYAQBgnSYTrDIzM/Xqq6/q0ksv9Vk+Z84czZ07V/PmzVNmZqbcbreGDRumwsJCb01KSooWL16stLQ0rVq1SkeOHFFCQoLKysq8NWPHjlV2drbS09OVnp6u7OxsJSYmeteXlZVp1KhROnr0qFatWqW0tDR98MEHmjp1av13vhYIVgAAWMg0AYWFhaZr165m2bJlZvDgwWbKlCnGGGPKy8uN2+02Tz/9tLe2qKjIuFwus2DBAmOMMYcPHzaBgYEmLS3NW7Nnzx4TEBBg0tPTjTHGbN261Ugya9eu9dasWbPGSDLfffedMcaYJUuWmICAALNnzx5vzXvvvWecTqfxeDw17ovH4zGSarVNbbz+ujGSMSNG1MvuAQBolmr6/t0kRqzuv/9+jRo1SkOHDvVZvmPHDuXl5Sk+Pt67zOl0avDgwVq9erUkKSsrS6WlpT41MTExiouL89asWbNGLpdL/fr189b0799fLpfLpyYuLk4xMTHemuuvv17FxcXKysryf6friOtYAQBgnZZWN+Bs0tLStGHDBmVmZlZZl5eXJ0mKjo72WR4dHa2dO3d6a4KCghQeHl6lpnL7vLw8RUVFVdl/VFSUT82pxwkPD1dQUJC3pjrFxcUqPmlerqCg4LS1/sBUIAAA1mnUI1a7du3SlClT9Pbbb6tVq1anrXM4HD6/G2OqLDvVqTXV1del5lSzZ8/2nhDvcrkUGxt7xnadK4IVAADWadTBKisrS/v371ffvn3VsmVLtWzZUhkZGXrhhRfUsmVL7wjSqSNG+/fv965zu90qKSlRfn7+GWv27dtX5fgHDhzwqTn1OPn5+SotLa0yknWy6dOny+PxeG+7du2q5V+hdghWAABYp1EHq+uuu06bNm1Sdna293bFFVdo3Lhxys7OVufOneV2u7Vs2TLvNiUlJcrIyNDAgQMlSX379lVgYKBPTW5urjZv3uytGTBggDwej9avX++tWbdunTwej0/N5s2blZub661ZunSpnE6n+vbte9o+OJ1OtW7d2udWnwhWAABYp1GfYxUWFqa4uDifZaGhoWrbtq13eUpKilJTU9W1a1d17dpVqampCgkJ0dixYyVJLpdLd911l6ZOnaq2bdsqIiJC06ZNU69evbwnw/fo0UPDhw9XUlKSXnnlFUnS3XffrYSEBHXv3l2SFB8fr549eyoxMVHPPvusDh06pGnTpikpKanew1JtVAaroiJr2wEAQHPUqINVTTz00EM6fvy4fve73yk/P1/9+vXT0qVLFRYW5q3585//rJYtW+rmm2/W8ePHdd1112nRokVq0aKFt+add97R5MmTvZ8eHDNmjObNm+dd36JFC3366af63e9+p6uuukrBwcEaO3as/vSnPzVcZ2sgJKTi/vhxa9sBAEBz5DDGGKsb0ZwUFBTI5XLJ4/HUy0jXjz9KXbtKYWFSPX8AEQCAZqOm79+N+hwr1F7liNWxYxKRGQCAhkWwspnKYFVWJpWWWtsWAACaG4KVzVQGK6li1AoAADQcgpXNBAZKlefkE6wAAGhYBCubcTik4OCKn/lkIAAADYtgZUMnn8AOAAAaDsHKhghWAABYg2BlQwQrAACsQbCyocpzrAhWAAA0LIKVDfG1NgAAWINgZUNMBQIAYA2ClQ0RrAAAsAbByoYIVgAAWINgZUOcvA4AgDUIVjZ03nkV90eOWNsOAACaG4KVDYWFVdwXFlrbDgAAmhuClQ21bl1xX1BgbTsAAGhuCFY2xIgVAADWIFjZUOWIFcEKAICGRbCyocoRK6YCAQBoWAQrG2IqEAAAaxCsbIipQAAArEGwsiGmAgEAsAbByoYqg9WRI1J5ubVtAQCgOSFY2VDlVKAkHT1qXTsAAGhuCFY21KqV1KJFxc9MBwIA0HAIVjbkcHACOwAAViBY2RRfawMAQMMjWNlUeHjFfX6+te0AAKA5IVjZVGWwOnTI2nYAANCcEKxsKiKi4p5gBQBAwyFY2VRlsGIqEACAhkOwsimmAgEAaHgEK5tiKhAAgIZHsLIpghUAAA2PYGVTnGMFAEDDI1jZFOdYAQDQ8AhWNsVUIAAADY9gZVMnBytjrG0LAADNBcHKptq2rbgvKZGOHLG2LQAANBcEK5sKDa24SdK+fda2BQCA5oJgZWPR0RX3BCsAABoGwcrGoqIq7vfvt7YdAAA0FwQrG2PECgCAhkWwsjGCFQAADYtgZWOVwYqpQAAAGgbBysYqz7FixAoAgIZBsLIxpgIBAGhYBCsbI1gBANCwCFY21r59xf3evXytDQAADYFgZWPnn19xf/So5PFY2xYAAJoDgpWNhYT833cG7t5tbVsAAGgOCFY2d8EFFfe7dlnbDgAAmgOClc3FxlbcM2IFAED9I1jZHCNWAAA0HIKVzTFiBQBAw2nUwWr27Nm68sorFRYWpqioKN144436/vvvfWqMMZo5c6ZiYmIUHBysIUOGaMuWLT41xcXFmjRpkiIjIxUaGqoxY8Zo9ylJIz8/X4mJiXK5XHK5XEpMTNThw4d9anJycjR69GiFhoYqMjJSkydPVklJSb303V8YsQIAoOE06mCVkZGh+++/X2vXrtWyZct04sQJxcfH6+jRo96aOXPmaO7cuZo3b54yMzPldrs1bNgwFRYWemtSUlK0ePFipaWladWqVTpy5IgSEhJUVlbmrRk7dqyys7OVnp6u9PR0ZWdnKzEx0bu+rKxMo0aN0tGjR7Vq1SqlpaXpgw8+0NSpUxvmj1FHlSNWBCsAABqAaUL2799vJJmMjAxjjDHl5eXG7Xabp59+2ltTVFRkXC6XWbBggTHGmMOHD5vAwECTlpbmrdmzZ48JCAgw6enpxhhjtm7daiSZtWvXemvWrFljJJnvvvvOGGPMkiVLTEBAgNmzZ4+35r333jNOp9N4PJ4a98Hj8RhJtdrmXPz4ozGSMa1aGVNW1iCHBADAdmr6/t2oR6xO5fnfq1xGRERIknbs2KG8vDzFx8d7a5xOpwYPHqzVq1dLkrKyslRaWupTExMTo7i4OG/NmjVr5HK51K9fP29N//795XK5fGri4uIUExPjrbn++utVXFysrKyseurxubvwQqlFC6moSMrNtbo1AADYW5MJVsYYPfjgg7r66qsVFxcnScrLy5MkRVd+Kd7/io6O9q7Ly8tTUFCQwsPDz1gTFRVV5ZhRUVE+NaceJzw8XEFBQd6a6hQXF6ugoMDn1pACA6UOHSp+/vHHBj00AADNTpMJVsnJyfr222/13nvvVVnncDh8fjfGVFl2qlNrqquvS82pZs+e7T0h3uVyKbbypKcG1KVLxf2//tXghwYAoFlpEsFq0qRJ+vjjj7VixQpdUPkxN0lut1uSqowY7d+/3zu65Ha7VVJSovz8/DPW7Nu3r8pxDxw44FNz6nHy8/NVWlpaZSTrZNOnT5fH4/HedllwFvlFF1XcE6wAAKhfjTpYGWOUnJysDz/8UMuXL1enTp181nfq1Elut1vLli3zLispKVFGRoYGDhwoSerbt68CAwN9anJzc7V582ZvzYABA+TxeLR+/Xpvzbp16+TxeHxqNm/erNyTTlRaunSpnE6n+vbte9o+OJ1OtW7d2ufW0AhWAAA0jJZWN+BM7r//fr377rv6+9//rrCwMO+IkcvlUnBwsBwOh1JSUpSamqquXbuqa9euSk1NVUhIiMaOHeutveuuuzR16lS1bdtWERERmjZtmnr16qWhQ4dKknr06KHhw4crKSlJr7zyiiTp7rvvVkJCgrp37y5Jio+PV8+ePZWYmKhnn31Whw4d0rRp05SUlGRJWKoNghUAAA2k3j+feA4kVXtbuHCht6a8vNzMmDHDuN1u43Q6zaBBg8ymTZt89nP8+HGTnJxsIiIiTHBwsElISDA5OTk+NQcPHjTjxo0zYWFhJiwszIwbN87k5+f71OzcudOMGjXKBAcHm4iICJOcnGyKiopq1aeGvtyCMcZ8+23FJRfatDGmvLzBDgsAgG3U9P3bYYwx1sW65qegoEAul0sej6fBRrqOHZPOO08yRtq3T6rmA5AAAOAMavr+3ajPsYJ/hIRIlaennfJtPwAAwI8IVs3EJZdU3G/dam07AACwM4JVM9GzZ8U9wQoAgPpDsGomKoMVU4EAANQfglUzwVQgAAD1j2DVTFx8ccX9gQMVNwAA4H8Eq2YiNFTq3Lni52+/tbYtAADYFcGqGenTp+J+wwZr2wEAgF0RrJoRghUAAPWLYNWMVH5XdFaWte0AAMCuCFbNSOWI1fbtksdjbVsAALAjglUzEhkpXXhhxc/Z2ZY2BQAAWyJYNTOVo1ZMBwIA4H8Eq2bmV7+quF+zxtp2AABgRwSrZuaqqyru//lPyRhr2wIAgN0QrJqZK6+UAgOl3Fxpxw6rWwMAgL0QrJqZ4OD/u+zCP/9pbVsAALAbglUzdPXVFferVlnbDgAA7IZg1QxVnmdFsAIAwL8IVs1Q5YjV1q3Svn3WtgUAADshWDVDkZHS5ZdX/Pz559a2BQAAOyFYNVPDhlXcL1tmbTsAALATglUzdXKw4npWAAD4B8Gqmbr6aqlVK2nvXmnbNqtbAwCAPRCsmqlWraRf/7ri53/8w9q2AABgFwSrZmzkyIr7jz+2th0AANgFwaoZu+GGivuvvpIOHrS2LQAA2AHBqhnr1Em69FKprEz69FOrWwMAQNNHsGrmbryx4v7vf7e0GQAA2ALBqpmrnA5MT5eOH7e2LQAANHUEq2bu8sulDh2kY8eYDgQA4FwRrJo5h0O69daKn995x9q2AADQ1BGsoHHjKu4//VQ6dMjatgAA0JQRrKBevSpupaXS3/5mdWsAAGi6CFaQ9H+jVkwHAgBQdwQrSJLGjq043+rLL6Xt261uDQAATRPBCpKk2FhpxIiKn1991dq2AADQVBGs4HXPPRX3CxdKxcXWtgUAgKaIYAWvkSOlCy6o+N7ADz6wujUAADQ9BCt4tWwp/fa3FT+//LK1bQEAoCkiWMHHb39bEbBWrZIyM61uDQAATQvBCj7OP1+67baKn//0J2vbAgBAU0OwQhXTplXc/+1v0k8/WdsWAACaEoIVqrj0Uik+Xiovl55/3urWAADQdBCsUK3/+I+K+//6Lykvz9q2AADQVBCsUK3rrpP69ZOOH5eeecbq1gAA0DQQrFAth0OaNavi55dflvbssbY9AAA0BQQrnNawYdLVV1dchT011erWAADQ+BGscFoOh/TEExU/v/YanxAEAOBsCFY4oyFDKkauSkulhx+2ujUAADRuBCuc1XPPSQEBFde1+vJLq1sDAEDjRbDCWfXqJd19d8XPKSlSWZmlzQEAoNEiWKFGZs2SWreWNm6UFi60ujUAADROBCvUSLt20syZFT8/9JC0b5+lzQEAoFEiWKHGJk2SLr9cys+vmBIEAAC+CFaosZYtKy67EBAgpaVJS5ZY3SIAABoXghVqpW9f6YEHKn6+7z7J47G2PQAANCYEqzqYP3++OnXqpFatWqlv37766quvrG5Sg3r8calTJyknR5o82erWAADQeBCsaun9999XSkqKHn30UW3cuFG//vWvNWLECOXk5FjdtAYTGiq99VbFlOCbb0p//avVLQIAoHFwGGOM1Y1oSvr166c+ffro5Zdf9i7r0aOHbrzxRs2ePfus2xcUFMjlcsnj8ah169b12dR699hj0lNPSeHh0vvvS8HBdduPw1H3NtR1W47JMTkmx+SYjX/bum7XocO5tbc6NX3/bunfw9pbSUmJsrKy9Mgjj/gsj4+P1+rVq6vdpri4WMXFxd7fCwoK6rWNDWnGDOkf/5C+/lqKj7e6NQAAVCguloKCrDk2waoWfvnlF5WVlSk6OtpneXR0tPLy8qrdZvbs2Xr88ccbonkNLjBQevddafz4iksw1EVdx0vPZZyVY3LMc92WY3JMjtl4j2k1glUdOE4ZXzTGVFlWafr06XrwwQe9vxcUFCg2NrZe29eQunaV1q2zuhUAADQOBKtaiIyMVIsWLaqMTu3fv7/KKFYlp9Mpp9PZEM0DAAAW41OBtRAUFKS+fftq2bJlPsuXLVumgQMHWtQqAADQWDBiVUsPPvigEhMTdcUVV2jAgAF69dVXlZOTo3vvvdfqpgEAAIsRrGrplltu0cGDBzVr1izl5uYqLi5OS5YsUYcOHaxuGgAAsBjXsWpgdrqOFQAAzUVN3785xwoAAMBPCFYAAAB+QrACAADwE4IVAACAnxCsAAAA/IRgBQAA4CcEKwAAAD8hWAEAAPgJwQoAAMBP+EqbBlZ5ofuCggKLWwIAAGqq8n37bF9YQ7BqYIWFhZKk2NhYi1sCAABqq7CwUC6X67Tr+a7ABlZeXq69e/cqLCxMDoejyvqCggLFxsZq165dtv0uQfpoH82hn/TRPppDP+lj/THGqLCwUDExMQoIOP2ZVIxYNbCAgABdcMEFZ61r3bq1bV8UleijfTSHftJH+2gO/aSP9eNMI1WVOHkdAADATwhWAAAAfkKwamScTqdmzJghp9NpdVPqDX20j+bQT/poH82hn/TRepy8DgAA4CeMWAEAAPgJwQoAAMBPCFYAAAB+QrACAADwE4JVPZs5c6YcDofPze12e9cbYzRz5kzFxMQoODhYQ4YM0ZYtW3z2UVxcrEmTJikyMlKhoaEaM2aMdu/e3dBdOaOOHTtW6afD4dD9998vSbrjjjuqrOvfv7/PPhpbP7/88kuNHj1aMTExcjgc+uijj3zW++uxy8/PV2Jiolwul1wulxITE3X48OF67l2FM/WxtLRUDz/8sHr16qXQ0FDFxMTo9ttv1969e332MWTIkCqP7a233upTY2UfpbM/lv56fjbWx1JSta9Ph8OhZ5991lvT2B/L2bNn68orr1RYWJiioqJ044036vvvv/epaeqvy7P10Q6vy5o8jk35NUmwagCXXHKJcnNzvbdNmzZ5182ZM0dz587VvHnzlJmZKbfbrWHDhnm/U1CSUlJStHjxYqWlpWnVqlU6cuSIEhISVFZWZkV3qpWZmenTx2XLlkmSfvOb33hrhg8f7lOzZMkSn300tn4ePXpUvXv31rx586pd76/HbuzYscrOzlZ6errS09OVnZ2txMTEeu+fdOY+Hjt2TBs2bNAf/vAHbdiwQR9++KF++OEHjRkzpkptUlKSz2P7yiuv+Ky3so/S2R9LyT/Pz8b6WEry6Vtubq5ef/11ORwO/fu//7tPXWN+LDMyMnT//fdr7dq1WrZsmU6cOKH4+HgdPXrUW9PUX5dn66MdXpc1eRylJvyaNKhXM2bMML179652XXl5uXG73ebpp5/2LisqKjIul8ssWLDAGGPM4cOHTWBgoElLS/PW7NmzxwQEBJj09PR6bfu5mDJlirnoootMeXm5McaYCRMmmBtuuOG09Y29n5LM4sWLvb/767HbunWrkWTWrl3rrVmzZo2RZL777rt67pWvU/tYnfXr1xtJZufOnd5lgwcPNlOmTDntNo2pj8ZU309/PD8bUz9r8ljecMMN5tprr/VZ1tQey/379xtJJiMjwxhjz9flqX2sTlN/XVbXx6b8mmTEqgFs375dMTEx6tSpk2699Vb99NNPkqQdO3YoLy9P8fHx3lqn06nBgwdr9erVkqSsrCyVlpb61MTExCguLs5b09iUlJTo7bff1sSJE32+aHrlypWKiopSt27dlJSUpP3793vXNbV++uuxW7NmjVwul/r16+et6d+/v1wuV6Pst8fjkcPhUJs2bXyWv/POO4qMjNQll1yiadOm+YwONJU+nuvzs6n0U5L27dunTz/9VHfddVeVdU3psfR4PJKkiIgISfZ8XZ7ax9PVNOXX5en62FRfk3wJcz3r16+f3nzzTXXr1k379u3Tk08+qYEDB2rLli3Ky8uTJEVHR/tsEx0drZ07d0qS8vLyFBQUpPDw8Co1lds3Nh999JEOHz6sO+64w7tsxIgR+s1vfqMOHTpox44d+sMf/qBrr71WWVlZcjqdTa6f/nrs8vLyFBUVVWX/UVFRja7fRUVFeuSRRzR27FifLz4dN26cOnXqJLfbrc2bN2v69On65ptvvNPBTaGP/nh+NoV+VnrjjTcUFhamm266yWd5U3osjTF68MEHdfXVVysuLs7bPsk+r8vq+niqpv66PF0fm/JrkmBVz0aMGOH9uVevXhowYIAuuugivfHGG94T8U4e1ZEqnminLjtVTWqs8pe//EUjRoxQTEyMd9ktt9zi/TkuLk5XXHGFOnTooE8//bTKP+4na8z9lPzz2FVX39j6XVpaqltvvVXl5eWaP3++z7qkpCTvz3FxceratauuuOIKbdiwQX369JHU+Pvor+dnY+9npddff13jxo1Tq1atfJY3pccyOTlZ3377rVatWlVlnV1el2fqo2SP1+Xp+tiUX5NMBTaw0NBQ9erVS9u3b/d+OvDU5Lx//37v/7jcbrdKSkqUn59/2prGZOfOnfr888/129/+9ox17du3V4cOHbR9+3ZJTa+f/nrs3G639u3bV2X/Bw4caDT9Li0t1c0336wdO3Zo2bJlPv8rrk6fPn0UGBjo89g29j6eqi7Pz6bSz6+++krff//9WV+jUuN9LCdNmqSPP/5YK1as0AUXXOBdbqfX5en6WMkOr8uz9fFkTek1SbBqYMXFxdq2bZvat2/vHaatHJqVKs5PysjI0MCBAyVJffv2VWBgoE9Nbm6uNm/e7K1pTBYuXKioqCiNGjXqjHUHDx7Url271L59e0lNr5/+euwGDBggj8ej9evXe2vWrVsnj8fTKPpd+Y/39u3b9fnnn6tt27Zn3WbLli0qLS31PraNvY/Vqcvzs6n08y9/+Yv69u2r3r17n7W2sT2WxhglJyfrww8/1PLly9WpUyef9XZ4XZ6tj1LTf13WpI+nalKvyXo7LR7GGGOmTp1qVq5caX766Sezdu1ak5CQYMLCwszPP/9sjDHm6aefNi6Xy3z44Ydm06ZN5rbbbjPt27c3BQUF3n3ce++95oILLjCff/652bBhg7n22mtN7969zYkTJ6zqVrXKysrMhRdeaB5++GGf5YWFhWbq1Klm9erVZseOHWbFihVmwIAB5vzzz2/U/SwsLDQbN240GzduNJLM3LlzzcaNG72fvPHXYzd8+HBz6aWXmjVr1pg1a9aYXr16mYSEBMv7WFpaasaMGWMuuOACk52dbXJzc7234uJiY4wxP/74o3n88cdNZmam2bFjh/n000/NxRdfbC6//PJG08ez9dOfz8/G+lhW8ng8JiQkxLz88stVtm8Kj+V9991nXC6XWblypc/z8dixY96apv66PFsf7fC6PFsfm/prkmBVz2655RbTvn17ExgYaGJiYsxNN91ktmzZ4l1fXl5uZsyYYdxut3E6nWbQoEFm06ZNPvs4fvy4SU5ONhERESY4ONgkJCSYnJychu7KWf3jH/8wksz333/vs/zYsWMmPj7etGvXzgQGBpoLL7zQTJgwoUofGls/V6xY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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "iters = np.arange(iterations)\n",
    "plt.plot(J_hist, iters, color='blue')\n",
    "plt.xlabel('Iterations')\n",
    "plt.ylabel('Cost')\n",
    "plt.title('Error vs. Training Epoch')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
